# /code/browser_ops.py
import asyncio
import os
from time import sleep

from playwright.async_api import async_playwright
from code.logger_config import logger
from code.config import USERAGENT
from code.utils import save_cookie


async def launch_browser():
    """启动浏览器并返回实例 - 使用playwright优化容器环境"""

    # 检测是否在容器环境中运行
    is_container = os.path.exists('/.dockerenv') or os.environ.get('CONTAINER') == 'true'

    try:
        logger.info("🚀 正在启动Playwright浏览器...")

        # 启动playwright
        playwright = await async_playwright().start()

        # 浏览器启动参数 - 针对容器环境优化
        browser_args = [
            "--no-sandbox",
            "--disable-setuid-sandbox",
            "--disable-dev-shm-usage",  # 关键：解决容器共享内存问题
            "--disable-gpu",
            "--disable-web-security",
            "--disable-features=VizDisplayCompositor",
            "--disable-extensions",
            "--disable-plugins",
            "--disable-images",
            "--disable-background-timer-throttling",
            "--disable-renderer-backgrounding",
            "--disable-backgrounding-occluded-windows",
            "--disable-ipc-flooding-protection",
            "--disable-hang-monitor",
            "--disable-popup-blocking",
            "--disable-sync",
            "--disable-translate",
            "--no-first-run",
            "--disable-default-apps",
            "--disable-domain-reliability",
            "--disable-component-extensions-with-background-pages",
            "--ignore-certificate-errors",
            "--ignore-ssl-errors",
            "--ignore-certificate-errors-spki-list",
            "--ignore-ssl-errors-list",
            f"--user-agent={USERAGENT}",
            "--window-size=1920,1080"
        ]

        # 容器环境特定配置
        if is_container:
            browser_args.extend([
                "--disable-audio-output",
                "--disable-background-mode",
                "--disable-extensions-file-access-check",
                "--disable-extensions-http-throttling",
                "--disable-sync-preferences",
                "--single-process",  # 容器中使用单进程模式
                "--memory-pressure-off",
                "--max_old_space_size=2048",
                "--disable-blink-features=AutomationControlled",
                "--disable-features=TranslateUI",
                "--disable-component-update",
                "--disable-background-networking",
                "--no-default-browser-check",
                "--disable-logging",
                "--disable-gpu-logging",
                "--log-level=3"
            ])
            logger.info("🐳 检测到容器环境，使用无头模式配置")
        else:
            browser_args.extend([
                "--start-maximized"
            ])
            logger.info("💻 检测到本地环境，使用有头模式配置")

        # 启动浏览器
        browser = await playwright.chromium.launch(
            headless=is_container,
            args=browser_args,
            timeout=90000 if is_container else 60000,  # 容器环境更长启动超时
            ignore_default_args=["--enable-automation"],
            handle_sigint=False,
            handle_sigterm=False,
            handle_sighup=False,
            slow_mo=0
        )

        logger.success("✅ Playwright浏览器启动成功")

        # 返回包装对象，保持与pyppeteer兼容的接口
        return BrowserWrapper(browser, playwright)

    except Exception as e:
        logger.error(f"❌ Playwright浏览器启动失败: {str(e)}")

        # 尝试最简化配置
        logger.info("🔄 尝试最简化浏览器配置...")
        try:
            playwright = await async_playwright().start()
            browser = await playwright.chromium.launch(
                headless=True,
                args=[
                    "--no-sandbox",
                    "--disable-setuid-sandbox",
                    "--disable-dev-shm-usage",
                    "--single-process",
                    "--disable-gpu",
                    f"--user-agent={USERAGENT}"
                ],
                timeout=120000  # 2分钟超时
            )
            logger.success("✅ 最简化配置启动成功")
            return BrowserWrapper(browser, playwright)
        except Exception as fallback_error:
            logger.error(f"❌ 最简化配置也失败: {str(fallback_error)}")
            raise


class BrowserWrapper:
    """浏览器包装类，提供与pyppeteer兼容的接口"""

    def __init__(self, browser, playwright):
        self.browser = browser
        self.playwright = playwright
        self._pages = []
        # 添加process属性以兼容定时任务检查
        self.process = MockProcess()

    async def newPage(self):
        """创建新页面 - playwright版本"""
        logger.info("📄 正在创建新页面...")
        try:
            context = await self.browser.new_context(
                viewport={'width': 1920, 'height': 1080},
                user_agent=USERAGENT,
                ignore_https_errors=True,
                java_script_enabled=True,
                accept_downloads=False,
                has_touch=False,
                is_mobile=False,
                locale='zh-CN',
                timezone_id='Asia/Shanghai',
                extra_http_headers={
                    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
                    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'
                }
            )

            page = await context.new_page()

            # 添加反检测脚本
            await page.add_init_script("""
                Object.defineProperty(navigator, 'webdriver', {
                    get: () => undefined
                });
                delete navigator.__proto__.webdriver;
                window.chrome = {
                    runtime: {}
                };
                Object.defineProperty(navigator, 'plugins', {
                    get: () => [1, 2, 3, 4, 5]
                });
                Object.defineProperty(navigator, 'languages', {
                    get: () => ['zh-CN', 'zh', 'en']
                });
            """)

            wrapped_page = PageWrapper(page, context)
            self._pages.append(wrapped_page)
            logger.success("✅ 页面创建成功")
            return wrapped_page

        except Exception as e:
            logger.error(f"❌ 页面创建失败: {str(e)}")
            raise

    async def close(self):
        """关闭浏览器"""
        try:
            # 关闭所有页面
            for page in self._pages:
                try:
                    await page.close()
                except:
                    pass

            await self.browser.close()
            await self.playwright.stop()
            # 标记process为已关闭
            self.process.returncode = 0
            logger.success("✅ 浏览器关闭成功")
        except Exception as e:
            logger.error(f"❌ 浏览器关闭失败: {str(e)}")


class MockProcess:
    """模拟进程对象，用于兼容性检查"""

    def __init__(self):
        self.returncode = None  # None表示进程仍在运行


class PageWrapper:
    """页面包装类，提供与pyppeteer兼容的接口"""

    def __init__(self, page, context):
        self.page = page
        self.context = context
        self._closed = False

    async def goto(self, url, options=None):
        """导航到URL"""
        if options is None:
            options = {}

        timeout = options.get('timeout', 30000)
        wait_until = options.get('waitUntil', 'domcontentloaded')

        # 转换waitUntil参数
        if wait_until == 'networkidle2':
            wait_until = 'networkidle'
        elif wait_until == 'domcontentloaded':
            wait_until = 'domcontentloaded'
        else:
            wait_until = 'load'

        return await self.page.goto(url, timeout=timeout, wait_until=wait_until)

    async def waitForSelector(self, selector, options=None):
        """等待选择器"""
        if options is None:
            options = {}

        timeout = options.get('timeout', 30000)
        return await self.page.wait_for_selector(selector, timeout=timeout)

    async def type(self, selector, text, options=None):
        """输入文本"""
        if options is None:
            options = {}

        delay = options.get('delay', 0)
        await self.page.fill(selector, text)
        if delay > 0:
            await asyncio.sleep(delay / 1000)

    async def click(self, selector, options=None):
        """点击元素"""
        if options is None:
            options = {}

        return await self.page.click(selector)

    async def cookies(self):
        """获取cookies"""
        cookies = await self.context.cookies()
        # 转换为pyppeteer格式
        return [
            {
                'name': cookie['name'],
                'value': cookie['value'],
                'domain': cookie['domain'],
                'path': cookie['path'],
                'expires': cookie.get('expires', -1),
                'httpOnly': cookie.get('httpOnly', False),
                'secure': cookie.get('secure', False),
                'sameSite': cookie.get('sameSite', 'Lax')
            }
            for cookie in cookies
        ]

    async def setCookie(self, *cookies):
        """设置cookies"""
        # 转换为playwright格式
        playwright_cookies = []
        for cookie in cookies:
            playwright_cookie = {
                'name': cookie['name'],
                'value': cookie['value'],
                'domain': cookie['domain'],
                'path': cookie['path']
            }
            if 'expires' in cookie and cookie['expires'] > 0:
                playwright_cookie['expires'] = cookie['expires']
            if 'httpOnly' in cookie:
                playwright_cookie['httpOnly'] = cookie['httpOnly']
            if 'secure' in cookie:
                playwright_cookie['secure'] = cookie['secure']
            if 'sameSite' in cookie:
                playwright_cookie['sameSite'] = cookie['sameSite']

            playwright_cookies.append(playwright_cookie)

        await self.context.add_cookies(playwright_cookies)

    async def content(self):
        """获取页面内容"""
        return await self.page.content()

    async def url(self):
        """获取当前URL"""
        return self.page.url

    async def title(self):
        """获取页面标题"""
        return await self.page.title()

    def setDefaultNavigationTimeout(self, timeout):
        """设置默认导航超时"""
        self.page.set_default_navigation_timeout(timeout)

    async def setViewport(self, viewport):
        """设置视口大小"""
        await self.page.set_viewport_size(viewport)

    async def setUserAgent(self, user_agent):
        """设置用户代理"""
        # 在playwright中，用户代理在context创建时设置，这里为兼容性保留
        pass

    async def setExtraHTTPHeaders(self, headers):
        """设置额外HTTP头"""
        await self.page.set_extra_http_headers(headers)

    async def evaluateOnNewDocument(self, script):
        """在新文档上执行脚本"""
        await self.page.add_init_script(script)

    def isClosed(self):
        """检查页面是否已关闭"""
        return self._closed or self.page.is_closed()

    async def close(self):
        """关闭页面"""
        if not self._closed:
            try:
                await self.page.close()
                await self.context.close()
                self._closed = True
            except Exception as e:
                logger.error(f"❌ 页面关闭失败: {str(e)}")


async def login(browser):
    """登录OA系统 - 使用playwright优化"""
    if os.getenv('DEBUG_MODE') == 'True':
        logger.debug("login =>")

    homepage = None
    try:
        # 检测容器环境
        is_container = os.path.exists('/.dockerenv') or os.environ.get('CONTAINER') == 'true'

        # 创建页面
        logger.info("📄 正在创建新页面...")
        homepage = await browser.newPage()

        # 设置超时
        timeout_ms = 120000 if is_container else 30000  # 容器环境2分钟超时
        logger.info(f"⏱️ 设置页面超时: {timeout_ms}ms")
        homepage.setDefaultNavigationTimeout(timeout_ms)

        # 访问OA系统
        oa_url = os.getenv('OA_HOST_URL')
        logger.info(f"🌐 正在访问OA系统: {oa_url}")

        try:
            await homepage.goto(oa_url, {
                'timeout': timeout_ms,
                'waitUntil': 'domcontentloaded'
            })
            logger.success("✅ OA系统页面加载完成")
        except Exception as e:
            logger.error(f"❌ OA系统访问失败: {str(e)}")
            # 尝试更简单的加载方式
            logger.info("🔄 尝试简化页面加载...")
            await homepage.goto(oa_url, {'timeout': timeout_ms})
            logger.success("✅ OA系统页面加载完成（简化模式）")

        if os.getenv('DEBUG_MODE') == 'True':
            logger.success("~~~~~~~~   reached the homepage of the OA            ~~~~~~~~")

        # 等待登录表单加载
        logger.info("⏳ 等待登录表单加载...")
        wait_timeout = 45000 if is_container else 10000

        try:
            await homepage.waitForSelector("#form > div > div.user > input", {'timeout': wait_timeout})
            logger.success("✅ 用户名输入框已找到")
        except Exception as e:
            logger.error(f"❌ 等待用户名输入框超时: {str(e)}")
            # 尝试等待更长时间
            logger.info("🔄 尝试更长等待时间...")
            await asyncio.sleep(5)
            await homepage.waitForSelector("#form > div > div.user > input", {'timeout': 60000})
            logger.success("✅ 用户名输入框已找到（重试成功）")

        # 输入用户名和密码
        username = os.getenv('USER_NAME')
        password = os.getenv('USER_PASSWORD')

        logger.info(f"👤 输入用户名: {username}")
        await homepage.type("#form > div > div.user > input", username)
        await asyncio.sleep(2)

        logger.info("🔐 输入密码...")
        await homepage.type("#form > div > div.pwd > input", password)
        await asyncio.sleep(2)

        # 点击登录按钮
        logger.info("🖱️ 点击登录按钮...")
        await homepage.click("#form > div > div.right > input")

        # 等待登录完成
        wait_time = 10 if is_container else 3
        logger.info(f"⏳ 等待登录完成 ({wait_time}秒)...")
        await asyncio.sleep(wait_time)

        if os.getenv('DEBUG_MODE') == 'True':
            logger.success("~~~~~~~~   logged into the homepage of the OA        ~~~~~~~~")

        # 保存cookie
        logger.info("🍪 保存登录Cookie...")
        try:
            cookieAfterLogin = await homepage.cookies()
            await save_cookie(cookieAfterLogin)
            logger.success("✅ Cookie保存成功")
        except Exception as e:
            logger.error(f"❌ Cookie保存失败: {str(e)}")

        if os.getenv('DEBUG_MODE') == 'True':
            logger.success("~~~~~~~~   today cookie was saved                    ~~~~~~~~")
            logger.debug("login <=\n")

        logger.success("✅ 登录流程完成")

    except Exception as e:
        logger.error(f"❌ 登录过程出错: {str(e)}")
        logger.error(f"❌ 错误类型: {type(e).__name__}")

        # 尝试获取页面信息用于调试
        if homepage:
            try:
                current_url = await homepage.url()
                logger.error(f"❌ 当前页面URL: {current_url}")
                page_title = await homepage.title()
                logger.error(f"❌ 页面标题: {page_title}")
            except Exception as debug_e:
                logger.error(f"❌ 获取调试信息失败: {str(debug_e)}")

        raise
    finally:
        # 不关闭页面，因为后续还需要使用
        pass


async def fetch_page_with_browser(browser, url):
    """使用浏览器获取页面内容（适用于需要JS分析的页面）"""
    if os.getenv('DEBUG_MODE') == 'True':
        logger.debug(f"fetch_page_with_browser => {url}")

    page = None
    try:
        logger.info("📄 正在创建页面获取内容...")
        page = await browser.newPage()

        await page.goto(url, {
            'timeout': 30000,
            'waitUntil': 'networkidle'
        })

        content = await page.content()

        if os.getenv('DEBUG_MODE') == 'True':
            logger.success(f"成功获取页面: {url}")

        return content

    except Exception as e:
        logger.error(f"浏览器获取页面失败: {str(e)}")
        return None
    finally:
        if page and not page.isClosed():
            try:
                await page.close()
            except Exception:
                pass